package com.gusto.engine.semsim.measures.impl;

import java.util.Map;

import org.apache.log4j.Logger;

import com.gusto.engine.semsim.exceptions.SimilarityException;
import com.gusto.engine.semsim.measures.CompoundValueSimilarity;
import com.gusto.engine.semsim.measures.ValueSimilarity;

/**
 * <p>Allows to calculate the similarity between two ZIP Codes.
 * Actually it is designed for codes on 5 positions.<br/>
 * By default :
 * <ul>
 * 	<li>level 1  :  75016  <->  75016  :  1.0 
 *  <li>level 2  :  7501x  <->  7501x  :  0.8
 *  <li>level 3  :  750xx  <->  750xx  :  0.8
 *  <li>level 4  :  75xxx  <->  75xxx  :  0.5
 *  <li>level 5  :  7xxxx  <->  7xxxx  :  0.1
 * </ul></p>
 * 
 * @author amokrane.belloui@gmail.com
 */
public class ZipCodeSimilarity implements ValueSimilarity, CompoundValueSimilarity {
	
	private Logger log = Logger.getLogger(getClass());
	
	private Double level1 = 1.0;
	private Double level2 = 0.8;
	private Double level3 = 0.8;
	private Double level4 = 0.5;
	private Double level5 = 0.1;
	
	public void setLevel1(Double level1) {
		this.level1 = level1;
	}
	public void setLevel2(Double level2) {
		this.level2 = level2;
	}
	public void setLevel3(Double level3) {
		this.level3 = level3;
	}
	public void setLevel4(Double level4) {
		this.level4 = level4;
	}
	public void setLevel5(Double level5) {
		this.level5 = level5;
	}
	
	public String getId() {
		String id = "[" + getClass().getName() + "|" +
				level1 + "|" + level2 + "|" + level3 + "|" + level4 + "|" + level5 +  "]";
		return id;
	}
	
	public Double getSimilarity(Object value1, Object value2) throws SimilarityException {
		try {
			String zip1 = value1 + "";
			String zip2 = value2 + "";
			Double sim = _getDefaultSimilarity(zip1, zip2);
			log.warn(sim);
			return sim;
		}
		catch (Exception ex) {
			throw new SimilarityException("This similarity is only applicable on String values", ex);
		}
	}
	
	public Double getSimilarity(Map<String, Object> values1, Map<String, Object> values2) throws SimilarityException {
		Double sim = _getSimilarity(
			values1.get("country").toString(), values1.get("zip").toString(), 
			values2.get("country").toString(), values2.get("zip").toString()
		);
		return sim;
	}
	
	private Double _getSimilarity(String country1, String zip1, String country2, String zip2) {
		if (country1 != null && country2 != null) {
			if (country1.equals(country2)) {
				Double sim = _getDefaultSimilarity(zip1, zip2);
				return sim;
			}
		}
		return 0.0;
	}
	
	private Double _getDefaultSimilarity(String zip1, String zip2) {
		if ( zip1.substring(0,5).equals(zip2.substring(0,5)) ) {
			log.info("Zip similarity (" + zip1 + ", " + zip2 + ") " + level1 + "");
			return level1;
		}
		else if ( zip1.substring(0,4).equals(zip2.substring(0,4)) ) {
			log.info("Zip similarity (" + zip1 + ", " + zip2 + ") " + level2 + "");
			return level2;
		}
		else if ( zip1.substring(0,3).equals(zip2.substring(0,3)) ) {
			log.info("Zip similarity (" + zip1 + ", " + zip2 + ") " + level3 + "");
			return level3;
		}
		else if ( zip1.substring(0,2).equals(zip2.substring(0,2)) ) {
			log.info("Zip similarity (" + zip1 + ", " + zip2 + ") " + level4 + "");
			return level4;
		}
		else if ( zip1.substring(0,1).equals(zip2.substring(0,1)) ) {
			log.info("Zip similarity (" + zip1 + ", " + zip2 + ") " + level5 + "");
			return level5;
		}
		log.info("Zip similarity (" + zip1 + ", " + zip2 + ") Default(" + 0.0 + ")");
		return 0.0;
	}
	
}
